#!/bin/sh
#
# wrsGenMultilib - generate multilib.h for VxWorks
#
# modification history
# --------------------
# 01b,17nov99,sn   weaken assumption to tool contains gnu 
#                  (rather than ends in gnu)
# 01a,15nov99,sn   wrote
#
# SYNOPSIS
# wrsGenMultilib target_suffix
#
# DESCRIPTION
# Output a 'C' header file containing multilib information
# for the given VxWorks architecture. 
#
# The information produced by this script serves two purposes:
#
# (i) It tells the multilib process what libraries to build.
# Recall that a VxWorks library is specified by a $(CPU)$(TOOL)
# combination: for example MIPS32sfgnu. Each library is built 
# with a set of flags defined in target/h/make.$(CPU)$(TOOL). 
# We tell the multilib process how to generate a corresponding
# set of GNU libraries. For example a version of libstdc++.a will 
# be built with the MIPS32sfgnu flags (including preprocessor defines)
# and put in a subdirectory named 'MIPS32sfgnu'.
#
# (ii) It enables the  compiler to decode any set of VxWorks flags into the 
# corresponding $(CPU)$(TOOL) subdirectory, e.g.
# ccmips -mcpu=r4000 -EB -mips3 -G0 -fno-for-scope --print-multi-dir
# => MIPS64gnu
# Note that (ii) is a nice bonus but not actually needed by
# the runtime at the moment.

# NOTE: In a slight abuse of terminology we use "flag" to mean a flag 
# (minus the leading hyphen) concatenated with its argument (if applicable) 
# with no intervening white space (G0, msoft-float, DCPU=MIPS32, EB). We 
# distinguish between argument taking flags (G0, DCPU=MIPS32) and non 
# argument taking flags (msoft-float, EB).

# The output consists of a number of C string arrays:
#
# multilib_raw contains one element for every multilib in the form:
#     {
#     "<subdir> <flag> ... <flag>;",
#     ... ,
#     NULL
#     }
#
# Here subdir=$(CPU)$(TOOL) to match the VxWorks notation.
#
# multilib_matches_raw lists the flags the decoder should recognize
# (the non argument taking flags)
#    {
#    "<flag> <same flag>;"
#    ... ,
#    NULL
#    }
#
# multilib_extra lists options that should be used to
# build every library: we just set this to "".
#
# MULTILIB_DEFAULTS (somewhat inappropriately named IMHO) lists the
# options appearing in multilib_raw which the decoder should ignore
# (it can't handle argument taking flags so we put those here)
#    {
#    "<option>",
#    ... ,
#    ""
#    }


# <Configuration data>

# [SALIM - 8 Nov 1999] The compiler libraries (e.g. tinfo.cc)
# will not compile with fno-builtin. (Although I  supect the only 
# changes required involve inserting  function prototypes/#include 
# directives). But even if we fixed that we would prefer to use 
# builtins.
# On the other hand the target side is compiled with -fno-builtin.
# This needs to be investigated (because removing it would be an 
# optimization; and if there's some deep reason why it is
# needed then we may also need to use it when building the
# compiler libraries).

# Remove certain flags that simply won't work with gnu libraries
# (such as ansi and pedantic). In principle each of these
# flags points to bugs/sloppiness in the gnu sources (-ansi, -pedantic)
# or VxWorks sources (-fno-for-scope) that need to be fixed.

no_include_flags="ansi pedantic fno-builtin fno-for-scope"

# Flags that take arguments can't be handled by the
# mechanism that decodes flags into multilib subdirectories.
# So we record that they should be used to build
# the relevant library but ignored for the purposes
# of determining the multilib location.
arg_taking_flags="G D"

# </Configuration data>

target_suffix=$1

# Sanity checks
test -z "$WIND_BASE" && echo "$0: Error: WIND_BASE must be set" 1>&2 && exit 1
test -z "$MAKE" && echo "$0: Error: MAKE not set" 1>&2 && exit 1
test -z "$target_suffix" && \
    echo "$0: Error: target suffix must be specified" 1>&2  && exit 1
test -d "$WIND_BASE/target/h/make" || \
    (echo "$0: Error: can't find $WIND_BASE/target/h/make" 1>&2 && exit 1)

# This is a hack. The correct fix is to make the
# target/h/make fragments independent of GCC_EXEC_PREFIX.
GCC_EXEC_PREFIX=

# location of this script
srcdir=`echo $0 | sed 's@/[^/]*$@@'`
# location of target files
tgtdir=$WIND_BASE/target

# a list containing "DCPU=$CPU" for each CPU
cpu_defines=
# the set of all flags used to build $target_suffix libraries
# (e.g. for mips this will contain mips1, mips3, mcpu=r3000, 
# mcpu=r4000 etc.)
flags=
# the subset of $flags in $arg_taking_flags
arg_flags=
# the subset of $flags not in $arg_taking_flags
non_arg_flags=

msg ()
{
    echo "$0: $@" 1>&2
}

msg "Generating multilib.h for $target_suffix"

# Output multilib_raw
echo 'static char *multilib_raw[] = {'

for makefrag in `cd ${tgtdir}/h/make; ls *gnu*`; do
    # run a makefile to generate a script that
    # sets CPU, TOOL, CC, CFLAGS
    output_of_make=/tmp/tmpwrsmlib.$$
    $MAKE --no-print-directory -f ${srcdir}/wrsExtractMultilibInfo \
        MAKEFRAG=${makefrag} \
        TGT_DIR=${tgtdir} >  $output_of_make
    # run the generated script
    . $output_of_make
    # CPU, TOOL, CC, CFLAGS are now set

    case "${CC}" in
        cc${target_suffix}* )
            # Some make fragments are just intended to be
            # included by other make fragments: they don't
            # correspond to actual libraries. So check for
            # the corresponding obj dir.
            if [ ! -d ${tgtdir}/lib//obj${CPU}${TOOL}vx ]; then
                msg "Ignoring $makefrag (no corresponding obj...vx dir)"
                continue
            fi

            msg "$0: Adding ${CPU}${TOOL} ..."

            # regexp matching one ore more whitespace characters
            ws="[	 ][	 ]*"
            # concatenate flags with their arguments (-G 0 -> -G0)
            CPU_flags=`echo $CFLAGS | \
                       sed "s@^\(-[^ ]*\)${ws}\([^-][^ ]*\)@\1\2@g; \
                            s@${ws}\(-[^ ]*\)${ws}\([^-][^ ]*\)@ \1\2@g"`
            # remove $no_include_flags
            for flag in $no_include_flags; do
                CPU_flags=`echo $CPU_flags | sed "s@-${flag}@@g"`
            done
            # remove leading hyphens
            CPU_flags=`echo $CPU_flags | sed "s@^-@@;s@${ws}-@ @g"`
            flags="$flags $CPU_flags"    
            cpu_defines="DCPU=$CPU $cpu_defines"
            # output a line of multilib_raw
            echo "  \"${CPU}${TOOL} DCPU=$CPU ${CPU_flags};\","
            ;;
    esac
done

echo "NULL"
echo "};"

# convert bags into sets
cpu_defines=`for flag in $cpu_defines; do echo $flag; done | sort -u`
flags=`for flag in $flags; do echo $flag; done | sort -u`

# divide $flags into $arg_flags and $non_arg_flags
arg_flags=$flags
# mark $arg_taking_flags by prepending a +
for flag in $arg_taking_flags; do
    # replace flag by +flag
    arg_flags=`echo $arg_flags | \
               sed "s@^${flag}@+${flag}@g;s@${ws}${flag}@ +${flag}@g"`
done
# replace remaining non + flags by whitespace.
arg_flags=`echo $arg_flags | sed "s@^[^+][^ ]*@@g;s@${ws}[^+][^ ]*@ @g"`

# and remove the leading + from the remaining flags.
arg_flags=`echo $arg_flags | sed "s@^+@@g;s@${ws}+@ @g"`
non_arg_flags=$flags
for flag in $arg_taking_flags; do
    # delete flag
    non_arg_flags=`echo $non_arg_flags | \
                   sed "s@^${flag}[^ ]*@@g;s@${ws}${flag}[^ ]*@ @g"`
done

# Output multilib_matches_raw
echo
echo 'static char *multilib_matches_raw[] = {'
for flag in $non_arg_flags; do
    echo "\"$flag $flag;\","
done
echo 'NULL'
echo '};'


# Output multilib_extra
echo
echo 'static char *multilib_extra = "";'
echo

# Output MULTILIB_DEFAULTS
echo '#ifdef MULTILIB_DEFAULTS'
echo '#undef MULTILIB_DEFAULTS'
echo '#endif'
echo '#define MULTILIB_DEFAULTS {\'
for flag in $arg_flags $cpu_defines; do
    echo "\"$flag\",\\"
done
echo '""\'
echo '}'
